package com.ndp.fb.rdb.mongo.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.*;
import com.ndp.fb.constant.MongoConstants;
import com.ndp.fb.model.AdSetStats;
import com.ndp.fb.mongo.api.AdSetStatsMongoService;
import com.ndp.fb.rdb.api.AdCampaignRdbService;
import com.ndp.fb.rdb.api.AdRdbService;
import com.ndp.fb.rdb.api.ConnectionObjectRdbService;
import com.ndp.fb.rdb.api.ProductConfigurationRdbService;
import com.ndp.fb.util.DateFormatUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by Hermen on 2015/3/6.
 */
@Service
public class AdSetStatsMongoServiceImpl implements AdSetStatsMongoService {
    /*所有的统计字段*/
    private static String[] SUM_FIELDS = {"clicks", "impressions", "results", "socialClicks", "socialImpressions", "socialSpent", "socialUniqueClicks", "socialUniqueImpressions", "spent", "uniqueClicks", "uniqueImpressions"};
    @Autowired
    AdCampaignRdbService adCampaignGroupRdbService;
    @Autowired
    ConnectionObjectRdbService connectionObjectRdbService;
    @Autowired
    ProductConfigurationRdbService productConfigurationRdbService;
    @Autowired
    AdRdbService adGroupRdbService;
    @Autowired
    private MongodbServiceImpl mongodbService;
    @Autowired
    private DB mongoDBClient;
    @Autowired
    private DB adHistoryDBClient;
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void batchSaveWithHistory(List<AdSetStats> adSetStatsList) {
        if (checkEmpty(adSetStatsList)) return;
        mongodbService.batchSaveOrUpdateWithHistory(mongoDBClient, MongoConstants.TABLE_NAME_ADSET_STATS_BY_DAY, JSONArray.toJSONString(adSetStatsList), new String[]{"mongodbId"}, adHistoryDBClient, MongoConstants.TABLE_NAME_ADSET_STATS_BY_DAY_HISTORY, false, new String[]{"campaignId"});
        logger.info("-----向mongoDB：" + MongoConstants.TABLE_NAME_ADSET_STATS_BY_DAY + "集合插入数据完成");
    }

    /**
     * 根据campaignId和时间范围查询统计数据（注意：只返回统计数据，业务数据返回值不可用）
     *
     * @param matchCampaignId campaignId过滤条件（必选参数）
     * @param matchSinceDay   查询开始日过滤条件（必选参数）
     * @param matchUntilDay   查询结束日过滤条件（必选参数）
     * @param returnFields    需要返回的字段过滤条件（可选参数）
     * @return 查询结果列表
     */
    @Override
    public List<AdSetStats> queryStatsDataByTimeRange(Long matchCampaignId, String matchSinceDay, String matchUntilDay, String... returnFields) {
        DBObject ref = new BasicDBObject();
        DBObject dayObject = new BasicDBObject();
        dayObject.put("$gte", matchSinceDay);
        dayObject.put("$lte", matchUntilDay);
        ref.put("day", dayObject);
        ref.put("campaignId", matchCampaignId);
        DBObject keys = new BasicDBObject();
        for (int i = 0; i < returnFields.length; i++) {
            keys.put(returnFields[i], 1);
        }
        DBCursor cursor = mongoDBClient.getCollection(MongoConstants.TABLE_NAME_ADSET_STATS_BY_DAY).find(ref, keys).addOption(Bytes.QUERYOPTION_NOTIMEOUT);
        List<AdSetStats> listAdSetStats = new ArrayList<>();
        try {
            while (cursor.hasNext()) {
                listAdSetStats.add(JSONObject.parseObject(JSON.toJSONString(cursor.next()), AdSetStats.class));
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            cursor.close();
        }
        return listAdSetStats;
    }

    @Override
    public AdSetStats getLatestSnap(Long adSetId, Date triggerPoint) {
        //match
        BasicDBObject matchObj = new BasicDBObject();
        matchObj.put("campaignId", adSetId);
        matchObj.put("day", new BasicDBObject("$lte", DateFormatUtil.formatLong10(triggerPoint)));

        //group
        DBObject groupCdt = new BasicDBObject();
        groupCdt.put("_id", new BasicDBObject("campaignId", "$campaignId"));
        groupCdt.put("updateTime", new BasicDBObject("$max", "$dataUpdateTime"));
        appendAllSumFields(groupCdt);

        List<DBObject> pipeline = new ArrayList<>();
        pipeline.add(new BasicDBObject("$match", matchObj));
        pipeline.add(new BasicDBObject("$group", groupCdt));
        logger.info("Mongo查询语句:" + com.mongodb.util.JSON.serialize(pipeline));

        long start = System.currentTimeMillis();
        AggregationOptions aggregationOptions = AggregationOptions.builder().allowDiskUse(true).build();
        Cursor cursor = mongoDBClient.getCollection(MongoConstants.TABLE_NAME_ADSET_STATS_BY_DAY).aggregate(pipeline, aggregationOptions);
        logger.info("Mongo聚合查询花费时间：" + (System.currentTimeMillis() - start) + "毫秒");
        try {
            if (cursor.hasNext()) {
                DBObject next = cursor.next();
                AdSetStats result = JSONObject.parseObject(JSON.toJSONString(next), AdSetStats.class);
                result.setCampaignId(adSetId);
                return result;
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        } finally {
            cursor.close();
        }

        return null;
    }

    /**
     * @param adSetStatsList
     * @discription
     * @author giser.yang
     * 创建时间 2015年7月3日 上午10:40:15
     * @see com.ndp.fb.mongo.api.AdSetStatsMongoService#batchSaveWithOutHistory(java.util.List)
     */

    @Override
    public void batchSaveWithOutHistory(List<AdSetStats> adSetStatsList) {
        if (checkEmpty(adSetStatsList)) return;
        mongodbService.batchSaveOrUpdateWithoutHistory(mongoDBClient, MongoConstants.TABLE_NAME_ADSET_STATS_BY_DAY, JSONArray.toJSONString(adSetStatsList), new String[]{"mongodbId"}, false);
        logger.info("-----向mongoDB：" + MongoConstants.TABLE_NAME_ADSET_STATS_BY_DAY + "集合插入数据完成");
    }

    private boolean checkEmpty(List<AdSetStats> adSetStatsList) {
        if (CollectionUtils.isEmpty(adSetStatsList)) {
            logger.info("AdSet统计数据入库列表为空，退出入库操作");
            return true;
        }
        return false;
    }

    private void appendAllSumFields(DBObject groupDBObject) {
        for (int i = 0; i < SUM_FIELDS.length; i++) {
            appendSumField(groupDBObject, SUM_FIELDS[i]);
        }
    }

    private void appendSumField(DBObject groupDBObject, String fieldName) {
        groupDBObject.put(fieldName, new BasicDBObject("$sum", "$" + fieldName));
    }

}
